/*  This file is part of -_-.

    -_- is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    -_- is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with -_-.  If not, see <http://www.gnu.org/licenses/>.

    Copyright 2012-2013 Oliver Katz */

#include "list.h"
#include "debug.h"

z_list z_list_init(z_size init)
{
	if (init == 0)
		Z_WARNING("cannot create empty list");

	z_list tmp;
	tmp.content = (z_data *)malloc(sizeof(z_data)*init);
	tmp.head = tmp.content;
	tmp.size = init;
	return tmp;
}

int z_list_release(z_list l)
{
	Z_WARNING_LIST(&l, 1);
	free(l.content);
	return 0;
}

z_size z_list_append(z_list *l, z_data e, z_size inc)
{
	Z_WARNING_LIST(l, 0);
	Z_WARNING_DATA(&e, 0);

	*(l->head++) = e;
	if (l->head-l->content >= l->size)
	{
		z_size old = l->size;
		l->size += inc;
		z_data *buf = (z_data *)malloc(sizeof(z_data)*l->size);
		memcpy(buf, l->content, old*sizeof(z_data));
		l->head += buf-l->content;
		l->content = buf;
	}
	return l->head-l->content-1;
}

z_data z_list_get(z_list *l, z_size idx)
{
	Z_WARNING_LIST(l, z_data_init(0, 0));

	if (idx < l->head-l->content)
		return l->content[idx];
	else
	{
		Z_WARNING("list overflow (%i >= %i)", idx, l->head-l->content);
		return z_data_init(0, 0);
	}
}

z_data z_list_set(z_list *l, z_size idx, z_data e)
{
	Z_WARNING_LIST(l, z_data_init(0, 0));
	Z_WARNING_DATA(&e, z_data_init(0, 0));

	if (idx < l->head-l->content)
		return (l->content[idx] = e);
	else
	{
		Z_WARNING("list overflow (%i >= %i)", idx, l->head-l->content);
		return z_data_init(0, 0);
	}
}

z_size z_list_size(z_list *l)
{
	Z_WARNING_LIST(l, 0);
	return l->head-l->content;
}

int z_list_remove(z_list *l, z_size idx)
{
	Z_WARNING_LIST(l, 1);
	
	if (idx >= l->head-l->content)
	{
		Z_WARNING("list overflow (%i >= %i)", idx, l->head-l->content);
		return 1;
	}

	memcpy(l->content+idx, l->content+idx+1, l->head-l->content-idx-1);
	l->head--;

	return 0;
}
